﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary
{
    /// <summary>
    /// This class represents a mathematical vector with 4 components. It should be primary used
    /// for geometric problems in a three dimensional space.
    /// </summary>
    [Serializable]
    public class GeneralVector4D : GeneralVector
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="GeneralVector4D"/> class.
        /// </summary>
        public GeneralVector4D()
            : base(4)
        {
            this.SetComponent(0, 0);
            this.SetComponent(1, 0);
            this.SetComponent(2, 0);
            this.SetComponent(3, 0);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GeneralVector4D"/> class.
        /// </summary>
        /// <param name="vector">The vector which should converted to a GeneralVector4D. Only the first
        /// four components of the specified vector will be set. If the vector includes more
        /// elements they will be thrown away.</param>
        public GeneralVector4D(GeneralVector vector)
            : base(4)
        {
            if (vector == (GeneralVector) null)
            {
                throw new ArgumentNullException("vector");
            }

            this.SetComponent(0, vector.GetComponent(0));
            this.SetComponent(1, vector.GetComponent(1));
            this.SetComponent(2, vector.GetComponent(2));
            this.SetComponent(3, vector.GetComponent(3));
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GeneralVector4D"/> class.
        /// </summary>
        /// <param name="vector">Another GeneralVector4D instance that should be cloned.</param>
        public GeneralVector4D(GeneralVector4D vector)
            : base(4)
        {
            if (vector == (GeneralVector4D) null)
            {
                throw new ArgumentNullException("vector");
            }

            this.SetComponent(0, vector.GetComponent(0));
            this.SetComponent(1, vector.GetComponent(1));
            this.SetComponent(2, vector.GetComponent(2));
            this.SetComponent(3, vector.GetComponent(3));
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GeneralVector4D"/> class.
        /// </summary>
        /// <param name="x">The first component of the vector(x).</param>
        /// <param name="y">The second component of the vector(y).</param>
        /// <param name="z">The third component of the vector(z).</param>
        /// <param name="w">The fourth component of the vector(w).</param>
        public GeneralVector4D(double x, double y, double z, double w)
            : base(4)
        {
            this.SetComponent(0, x);
            this.SetComponent(1, y);
            this.SetComponent(2, z);
            this.SetComponent(3, w);
        }

        /// <summary>
        /// Gets or sets the x value of the GeneralVector4D.
        /// </summary>
        /// <value>The x value of the GeneralVector4D.</value>
        public double X
        {
            get { return this.GetComponent(0); }
            set { this.SetComponent(0, value); }
        }

        /// <summary>
        /// Gets or sets the y value of the GeneralVector4D.
        /// </summary>
        /// <value>The y value of the GeneralVector4D.</value>
        public double Y
        {
            get { return this.GetComponent(1); }
            set { this.SetComponent(1, value); }
        }

        /// <summary>
        /// Gets or sets the z value of the GeneralVector4D.
        /// </summary>
        /// <value>The z value of the GeneralVector4D.</value>
        public double Z
        {
            get { return this.GetComponent(2); }
            set { this.SetComponent(2, value); }
        }

        /// <summary>
        /// Gets or sets the w value of the GeneralVector4D.
        /// </summary>
        /// <value>The w value of the GeneralVector4D.</value>
        public double W
        {
            get { return this.GetComponent(3); }
            set { this.SetComponent(3, value); }
        }

        /// <summary>
        /// Implements the operator +.
        /// </summary>
        /// <param name="a">The first GeneralVector4D.</param>
        /// <param name="b">The second GeneralVector4D.</param>
        /// <returns>The result of the operator.</returns>
        public static GeneralVector4D operator +(GeneralVector4D a, GeneralVector4D b)
        {
            if (a == (GeneralVector4D) null)
            {
                throw new ArgumentNullException("a");
            }

            if (b == (GeneralVector4D) null)
            {
                throw new ArgumentNullException("b");
            }

            return new GeneralVector4D(a.ToVector() + b.ToVector());
        }

        /// <summary>
        /// Implements the operator -.
        /// </summary>
        /// <param name="a">The first GeneralVector4D.</param>
        /// <param name="b">The second GeneralVector4D.</param>
        /// <returns>The result of the operator.</returns>
        public static GeneralVector4D operator -(GeneralVector4D a, GeneralVector4D b)
        {
            if (a == (GeneralVector4D) null)
            {
                throw new ArgumentNullException("a");
            }

            if (b == (GeneralVector4D) null)
            {
                throw new ArgumentNullException("b");
            }

            return new GeneralVector4D(a.ToVector() - b.ToVector());
        }

        /// <summary>
        /// Implements the operator *.
        /// </summary>
        /// <param name="a">The first GeneralVector4D.</param>
        /// <param name="b">The second GeneralVector4D.</param>
        /// <returns>The result of the operator.</returns>
        public static double operator *(GeneralVector4D a, GeneralVector4D b)
        {
            if (a == (GeneralVector4D) null)
            {
                throw new ArgumentNullException("a");
            }

            if (b == (GeneralVector4D) null)
            {
                throw new ArgumentNullException("b");
            }

            return a.ToVector() * b.ToVector();
        }

        /// <summary>
        /// Implements the operator *.
        /// </summary>
        /// <param name="value">The scalar value with which the vector should be multiplied.</param>
        /// <param name="a">The GeneralVector4D instance.</param>
        /// <returns>The result of the operator.</returns>
        public static GeneralVector4D operator *(double value, GeneralVector4D a)
        {
            if (a == (GeneralVector4D) null)
            {
                throw new ArgumentNullException("a");
            }

            return new GeneralVector4D(value * a.ToVector());
        }

        /// <summary>
        /// Implements the operator *.
        /// </summary>
        /// <param name="a">The GeneralVector4D instance.</param>
        /// <param name="value">The scalar value with which the vector should be multiplied.</param>
        /// <returns>The result of the operator.</returns>
        public static GeneralVector4D operator *(GeneralVector4D a, double value)
        {
            if (a == (GeneralVector4D) null)
            {
                throw new ArgumentNullException("a");
            }

            return new GeneralVector4D(a.ToVector() * value);
        }

        /// <summary>
        /// Converts the GeneralVector4D to a normal n-dimensional vector.
        /// </summary>
        /// <returns>The converted vector.</returns>
        public GeneralVector ToVector()
        {
            return new GeneralVector(this.VectorData);
        }
    }
}